package schedule;


import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import dsx.config.Config;
import dsx.console.DsxConsole;
import dsx.inf.IBizStartModule;
import dsx.inf.ITask;
import dsx.log.ServLog;
import dsx.system.ThreadEx;

public class Schedule extends ThreadEx implements IBizStartModule {
	static HashMap<String, _Task> configMap = null;
	static HashMap<String, ITask> taskMap = new HashMap<String, ITask>();
	static ArrayList<TaskTimer> timerList = new ArrayList<TaskTimer>();
	TimerThread timer = null;
	
	class TaskTimer {
		String type;
		boolean flag;	// 待执行标识，false 未等待执行，true 等待执行
		boolean byTiming;
		int counter;
	}

	class TimerThread extends ThreadEx {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		@Override
		protected void doInLoop() {
			for (TaskTimer taskTimer : timerList) {
				synchronized (taskTimer) {
					try {
						_Task config = configMap.get(taskTimer.type);
						if (taskTimer.byTiming) {
							taskTimer.counter--;
							if (taskTimer.counter <= 0){
								taskTimer.flag = true;
								taskTimer.counter = config.interver;
							}
						} else {
							Date now = new Date();
							String[] execTime = config.execTime.split(",");
							for (int i = 0; i < execTime.length; i++) {
								String strTime = String.format("%s %s",
										dateFormat.format(now), execTime[i]);
								Date time = timeFormat.parse(strTime);
								// 前后3秒是有效执行时间范围
								if (Math.abs(now.getTime() - time.getTime() - 3000) < 3000) {
									if (taskTimer.counter <= 0) {
										taskTimer.flag = true;
										// 冷却10秒，从而避免重复执行
										taskTimer.counter = 10;	
									} else {
										taskTimer.counter--;
									}
								}
							}
						}
					} catch (Exception ex) {
					}
				}
			}
		}
	}
	
	@Override
	public void initialize() {
		try {
			configMap = loadConfig();
			timer = new TimerThread();
			timer.setInterval(1000);
			this.setInterval(1000);
			if (configMap != null) {
				for (Entry<String, _Task> entry : configMap.entrySet()) {
					_Task config = entry.getValue();
					TaskTimer taskTimer = new TaskTimer();
					taskTimer.type = config.type;
					taskTimer.flag = false;
					if (config.execTime.equals("")) {
						taskTimer.byTiming = true;
						taskTimer.counter = config.interver;
					} else {
						taskTimer.byTiming = false;
						taskTimer.counter = 0;
					}
					timerList.add(taskTimer);
				}
			}
			start();
			timer.start();
		} catch (Exception ex) {

		}
	}

	@Override
	public void finalize() {
		try {
			timer.stopEx();
			stopEx();
			configMap.clear();
			taskMap.clear();
			timerList.clear();
		} catch (Exception ex) {

		}
	}

	@Override
	protected void doInLoop() {
		for (TaskTimer taskTimer : timerList) {
			try {
				if (taskTimer.flag) {
					synchronized (taskTimer) {
						taskTimer.flag = false;
					}
					execTask(taskTimer.type);
				}
			} catch (Exception ex) {
			}
		}
	}

	public static boolean execTask(String type) {
		try {
			ITask task = taskMap.get(type);
			if (task == null) {
				_Task config = configMap.get(type);
				if (config == null)
					return false;
				String path = Config.get("task", "path");
				URLClassLoader classLoader = getClassLoader(path + config.lib);
				if (classLoader == null)
					return false;

				task = (ITask) classLoader.loadClass(config.className)
						.newInstance();
				if (task == null)
					return false;

				synchronized (taskMap) {
					taskMap.put(config.type, task);
				}
			}

			synchronized (task) {
				return task.doJob();
			}
		} catch (Exception ex) {
			return false;
		}
	}

	public static ArrayList<_Task> getTaskList() {
		if (configMap == null)
			return null;
		ArrayList<_Task> taskList = new ArrayList<_Task>();
		for (Entry<String, _Task> entry : configMap.entrySet()) {
			taskList.add(entry.getValue());
		}
		return taskList;
	}
	
	private static synchronized URLClassLoader getClassLoader(String lib) {
		try {
			if (lib.equals("")) {
				return (URLClassLoader) Thread.currentThread()
						.getContextClassLoader();
			}
			URL url = new File(lib).toURI().toURL();
			URLClassLoader classLoader = new URLClassLoader(new URL[] { url },
					Thread.currentThread().getContextClassLoader());
			return classLoader;
		} catch (Exception ex) {
			return null;
		}
	}

	private static HashMap<String, _Task> loadConfig() throws Exception {
		String path = Config.get("task", "path");
		HashMap<String, _Task> ret = new HashMap<String, _Task>();
		Config.lockConfig("task");
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document document = db.parse(new File(String.format("%stask.xml",
					path)));
			Element root = document.getDocumentElement();
			NodeList modules = root.getElementsByTagName("Task");
			int moduleNum = modules.getLength();
			for (int i = 0; i < moduleNum; i++) {
				_Task config = new _Task();
				Element elem = (Element) modules.item(i);
				config.type = Config.getNodeValue(elem, "type");
				config.name = Config.getNodeValue(elem, "name");
				config.lib = Config.getNodeValue(elem, "lib");
				config.className = Config.getNodeValue(elem, "class");
				config.execTime = Config.getNodeValue(elem, "execTime");
				String interval = Config.getNodeValue(elem, "interval");
				if (interval.isEmpty())
					config.interver = 0;
				else
					config.interver = Integer.parseInt(interval);
				ret.put(config.type, config);
			}
		} catch (Exception ex) {
			DsxConsole.out(ex.getMessage(), "task", ServLog.error);
		} finally {
			Config.releaseConfig("task");
		}
		return ret;
	}

}
